/**
 * Defines the initial Android user to be used during initialization.
 *
 * This property is called by the Android system when it initializes and it lets the HAL
 * define which Android user should be started.
 *
 * This request is made by setting a VehiclePropValue (defined by InitialUserInfoRequest),
 * and the HAL must respond with a property change event (defined by InitialUserInfoResponse).
 * If the HAL doesn't respond after some time (defined by the Android system), the Android
 * system will proceed as if HAL returned a response of action
 * InitialUserInfoResponseAction:DEFAULT.
 *
 * For example, on first boot, the request could be:
 *
 * int32[0]: 42  // request id (arbitrary number set by Android system)
 * int32[1]: 1   // InitialUserInfoRequestType::FIRST_BOOT
 * int32[2]: 0   // id of current user (usersInfo.currentUser.userId)
 * int32[3]: 1   // flag of current user (usersInfo.currentUser.flags = SYSTEM)
 * int32[4]: 1   // number of existing users (usersInfo.numberUsers);
 * int32[5]: 0   // user #0  (usersInfo.existingUsers[0].userId)
 * int32[6]: 1   // flags of user #0  (usersInfo.existingUsers[0].flags)
 *
 * And if the HAL want to respond with the creation of an admin user called "Owner", the
 * response would be:
 *
 * int32[0]: 42      // must match the request id from the request
 * int32[1]:  2      // action = InitialUserInfoResponseAction::CREATE
 * int32[2]: -10000  // userToSwitchOrCreate.userId (not used as user will be created)
 * int32[3]:  8      // userToSwitchOrCreate.flags = ADMIN
 * string: "||Owner" // userLocales + separator + userNameToCreate
 *
 * Notice the string value represents multiple values, separated by ||. The first value is the
 * (optional) system locales for the user to be created (in this case, it's empty, meaning it
 * will use Android's default value), while the second value is the (also optional) name of the
 * to user to be created (when the type of response is InitialUserInfoResponseAction:CREATE).
 * For example, to create the same "Owner" user with "en-US" and "pt-BR" locales, the string
 * value of the response would be "en-US,pt-BR||Owner". As such, neither the locale nor the
 * name can have || on it, although a single | is fine.
 *
 * NOTE: if the HAL doesn't support user management, then it should not define this property,
 * which in turn would disable the other user-related properties (for example, the Android
 * system would never issue them and user-related requests from the HAL layer would be ignored
 * by the Android System). But if it supports user management, then it must support all core
 * user-related properties (INITIAL_USER_INFO, SWITCH_USER, CREATE_USER, and REMOVE_USER).
 *
 * @change_mode VehiclePropertyChangeMode:ON_CHANGE
 * @access VehiclePropertyAccess:READ_WRITE
 */

#include "PlatformProperty.h"
#include "UserHalHelper.h"

using namespace user_hal_helper;

SYSTEM_READ_WRITE_PROPERTY(INITIAL_USER_INFO, MixedValue) {
    builder.area(VehicleArea::GLOBAL)
        .initValue([]() {
            MixedValue ret = {
                .int32Values = {0},
                .floatValues = {0.0f},
                .int64Values = {0},
                .bytes = {0x00},
                .stringValue = "INITIAL_USER_INFO",
            };
            return ret;
        })
        .immutableStatus(PropertyStatus::Active)
        .withValueBySignals([](const MixedValue &value) {
            return value;
        })
        .onSetProperty([this](const MixedValue &value) {
            auto initialUserInfoRequest = toInitialUserInfoRequest(value);
            if (!initialUserInfoRequest.ok()) {
                ALOGE("INITIAL_USER_INFO: toInitialUserInfoRequest failed: %s", initialUserInfoRequest.error().message().c_str());
                return;
            }
            if (initialUserInfoRequest->requestId == INVALID_REQUEST_ID) {
                ALOGE("INITIAL_USER_INFO: initialUserInfoRequest requestId is invalid -1");
                return;
            }
            ALOGD("INITIAL_USER_INFO: initialUserInfoRequest:= %s", toString(initialUserInfoRequest.value()).c_str());

            InitialUserInfoResponse initialUserInfoResponse = {
                .requestId = initialUserInfoRequest->requestId,
                .action = InitialUserInfoResponseAction::DEFAULT,
            };

            std::string stringPidToUids = this->getPlatformProfile()->getAuxiliary()->getString(PROFILE_ID_TO_USER_ID, "");

            // 如果是系统首次开机默认创建Guest用户并且切换，并且绑定profile_13与userd10
            if (initialUserInfoRequest->requestType == InitialUserInfoRequestType::FIRST_BOOT) {
                initialUserInfoResponse.action = InitialUserInfoResponseAction::CREATE;
                initialUserInfoResponse.userToSwitchOrCreate.userId = -10000;
                initialUserInfoResponse.userToSwitchOrCreate.flags = UserFlags::GUEST;
                initialUserInfoResponse.userNameToCreate = "GUEST";
                stringPidToUids = relationPidToUidsString(FITST_USER_ID, GUEST_PROFILE_ID, stringPidToUids);
            } else if (initialUserInfoRequest->requestType == InitialUserInfoRequestType::COLD_BOOT) {
            // 系统正常启动需要删除profile_12映射，因为FWK层会将创建的临时用户删除
                if (getUserId(stringPidToUids, EPHEMERAL_PROFILE_ID) != INVALID_USER_ID) {
                    stringPidToUids = removeRelationPidToUidsString(EPHEMERAL_PROFILE_ID, stringPidToUids);
                }
                // 如果上次退出时处于临时用户需要默认切换至游客用户
                // 如果上次退出时处于其他用户需要响应FWK切换至相应用户
                int32_t targetProfileId = getCurrentProfileID();
                if (targetProfileId == EPHEMERAL_PROFILE_ID) {
                    targetProfileId = GUEST_PROFILE_ID;
                    this->getPlatformProfile()->activeProfile(targetProfileId);
                }
                int targetUserId = getUserId(stringPidToUids, targetProfileId);
                if (targetUserId != INVALID_USER_ID) {
                    for (auto user : initialUserInfoRequest->usersInfo.existingUsers) {
                        if (user.userId == targetUserId) {
                            initialUserInfoResponse.action = InitialUserInfoResponseAction::SWITCH;
                            initialUserInfoResponse.userToSwitchOrCreate = user;
                            break;
                        }
                    }
                }
            }

            this->getPlatformProfile()->getAuxiliary()->setString(PROFILE_ID_TO_USER_ID, stringPidToUids);
            this->getPlatformProfile()->getAuxiliary()->save();

            ALOGD("INITIAL_USER_INFO: initialUserInfoResponse:= %s", toString(initialUserInfoResponse).c_str());
            setValue(static_cast<int32_t>(VehicleArea::GLOBAL), toVehiclePropValue(initialUserInfoResponse)->value, true);
        });
}